
`include "common_header.verilog"

//  *************************************************************************
//  File : decode64.v
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2008 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Thomas Schrobenhauser
//  info@morethanip.com
//  *************************************************************************
//  Description : 10G/100G Base-R PCS Block Decoder Top Level Structure
//  Version     : $Id: decode64.v,v 1.9 2015/11/19 14:41:57 wt Exp $
//  *************************************************************************

module decode64 (

        reset,
        clk,
        ck_ena,
        data_0_in,
        sh_0_in,

`ifdef MTIPPCS_EEE_ENA
        rx_lpi_active,
        r_type_li,
        r_type_c,
        r_type_val,
`endif

	ena_clause49,
        loopback_ena,
        cgmii_txclk_ena,
        cgmii_txc,
        cgmii_txd,
        r_test_mode,
        block_lock,
        hi_ber,
`ifdef MTIP_DEBUG_BUSES
        decode_val,
        dec_error,        
`endif
        err_block_count_rd,
        err_block_count,
        rx_d_out,
        rx_c_out,
        xlgmii_rxt0_next,
        rx_val_out);

input                   reset;                  //  asynch reset
input                   clk;                    //  system clock
input                   ck_ena;                 //  clock enable
input   [63:0]          data_0_in;              //  data input
input   [1:0]           sh_0_in;                //  sync header

input  			ena_clause49;		//  Enable Clause 49 (1) or Clause 82 (0) PCS encoder/decoder 
input                   loopback_ena;           //  XL/CGMII loopback enable
input                   cgmii_txclk_ena;        //  XL/CGMII clock enable to control loopback
input   [7:0]           cgmii_txc;              //  XL/CGMII transmit control
input   [63:0]          cgmii_txd;              //  XL/CGMII transmit data
input                   r_test_mode;            //  Receive test pattern mode
input                   block_lock;             //  Lock state reached
input                   hi_ber;                 //  High Bit Error
input                   err_block_count_rd;     //  Block error counter has been read
`ifdef MTIP_DEBUG_BUSES
output                  decode_val;             // if 1 decoding is possible, otherwise local fault is generated
output                  dec_error;              //  per block decode error indication           
`endif

output  [21:0]          err_block_count;        //  Block error counter to be read
output  [63:0]          rx_d_out;               //  data to XL/CGMII bus
output  [7:0]           rx_c_out;               //  control to from XL/CGMII bus
output                  xlgmii_rxt0_next;       //  Advance indication if TERM block without data is next after current 
                                                // (directly from decoder classification block type 0x87, T0)       

output                  rx_val_out;             //  output valid (clock-enable out)
`ifdef MTIPPCS_EEE_ENA
input                   rx_lpi_active;          // A Boolean variable that is set to true when the RS-FEC sublayer infers that the Low Power Idle is
                                                // being received from the link partner and is set to false otherwise.
output                  r_type_li;              // LPI Block Received
output                  r_type_c;               // C block Received
output                  r_type_val;             // data_val(clk enable) for the r_type_li and r_type_c

wire                    r_type_li;
wire                    r_type_c;
wire                    r_type_val;

`endif

wire    [21:0]          err_block_count; 
reg     [63:0]          rx_d_out; 
reg     [7:0]           rx_c_out; 
reg                     rx_val_out; 



wire                    clk_ena_out;            //  aligned with pipeline from ck_ena from 1st block decoder

wire                    r_type_c_0;             //  C Block type received
wire                    r_type_s_0;             //  S Block type received
wire                    r_type_t_0;             //  T Block type received
wire                    r_type_d_0;             //  D Block type received
wire                    r_type_edt_0;           //  E+D+T Block type received

`ifdef MTIPPCS_EEE_ENA
wire                    r_type_li_0;            // LPI Block received

`endif
wire    [63:0]          rx_d_0;                 //  Data out in CGMII format
wire    [7:0]           rx_c_0;                 //  Control lane for CGMII format


//  stored lane 2
reg                     r_type_c_0r0;           //  C Block type received
`ifdef MTIPPCS_EEE_ENA
reg                     r_type_li_0r0;          // LPI Block received
`endif
reg                     r_type_s_0r0;           //  S Block type received
reg                     r_type_t_0r0;           //  T Block type received
reg                     r_type_d_0r0;           //  D Block type received

// ----------------------
//  BLOCK_CHECK signals
// ----------------------
reg                     hi_ber_s;               //  pipe alignment for error counters
wire                    init_cond;              //  r_test_mode + hi_ber + !align_status
wire                    err_count_ena;          //  inverse of init_cond enable the block error counter

`ifdef MTIPPCS_EEE_ENA
reg     [2:0]           state_in_0;             //  current state
wire    [2:0]           state_next_0;           //  next state

`else
reg     [1:0]           state_in_0;             //  current state
wire    [1:0]           state_next_0;           //  next state

`endif

wire                    error_out_0;            //  error should be sent 
wire                    rx_init_out_0;          //  RX_INIT state => produce local fault

// =======================================================================
wire                    dec_error;        //  per block decode error indication
reg     [3:0]           loopback_ena_s;   //  XL/CGMII loopback enable

wire                    xlgmii_rxt0_next_int;
reg                     xlgmii_rxt0_next;
reg     [63:0]          cgmii_txd_r;
reg     [7:0]           cgmii_txc_r;
reg     [63:0]          rx_d_0r0;       //  Data out in CGMII format
reg     [7:0]           rx_c_0r0;       //  Control lane for CGMII format

wire convert2clause82;
wire convert2clause82_err;
wire [63:0] rx_d_int;
wire [7:0] rx_c_int;

`ifdef MTIP_DEBUG_BUSES
wire            decode_val;
assign  decode_val = ~init_cond;           
`endif


`ifdef MTIPPCS_EEE_ENA
assign  r_type_li       = r_type_li_0;
assign  r_type_c        = r_type_c_0;
assign  r_type_val      = clk_ena_out; 
`endif


// =============================================================
//  First stage: decode all blocks independently into CGMII blocks
//  not implementing the statemachine yet, as it always requies 
//  next block to decide if block must be errored out.
// =============================================================

p8264_block_type_decode U_BLOCKDEC0 (

        .reset          (reset),
        .clk            (clk),
        .clk_ena        (ck_ena),
        .data_in        (data_0_in),
        .sh_in          (sh_0_in),
        .clk_ena_out    (clk_ena_out), //  pipeline aligned clock-enable for all output processing.
        .rx_d           (rx_d_0),
        .rx_c           (rx_c_0),
        .r_type_c       (r_type_c_0), //  C Block type received
`ifdef MTIPPCS_EEE_ENA
        .r_type_li      (r_type_li_0), // LPI Block received
`endif
        .r_type_s       (r_type_s_0), //  S Block type received
        .r_type_t       (r_type_t_0), //  T Block type received        
        .xlgmii_rxt0_next(xlgmii_rxt0_next_int),
        .r_type_d       (r_type_d_0), //  D Block type received
        .r_type_edt     (r_type_edt_0));



assign  convert2clause82 = 	((rx_d_0[7:0]==8'h 9C | rx_d_0[7:0]==8'h 5C) & 
				  rx_d_0[63:32]==32'h 07070707 & 
				  rx_c_0[7:0] == 8'h F1 &
				  ena_clause49 == 1'b 0);

assign convert2clause82_err = ((rx_d_0[7:0]==8'h 9C | rx_d_0[7:0]==8'h 5C) & 
				  rx_d_0[63:32]==32'h FEFEFEFE & 
				  rx_c_0[7:0] == 8'h F1 &
				  ena_clause49 == 1'b 0);

assign rx_d_int[63:32] = (convert2clause82==1'b 1) ? 32'd 0 : rx_d_0[63:32];
assign rx_d_int[31:0]  = (convert2clause82_err==1'b 1) ? 32'h FEFEFEFE : rx_d_0[31:0];
assign rx_c_int[7:4]   = (convert2clause82==1'b 1) ? 4'd 0 : rx_c_0[7:4];
assign rx_c_int[3:0]   = (convert2clause82_err==1'b 1) ? 4'h F : rx_c_0[3:0];

//  ------------------------------------------------------------
//  to validate each block the RX statemachine requires the edt value of the next block.
//  Hence we can only decode blocks 0,1 but not block 2 at the same time.
//  Block 2 needs to be delayed and then combined with the next blocks 0,1 to form a complete 3-block output.
//  ------------------------------------------------------------

always @(posedge reset or posedge clk)
begin : process_1
        if (reset == 1'b 1)
        begin
                r_type_c_0r0    <= 1'b 0;
`ifdef MTIPPCS_EEE_ENA
                r_type_li_0r0   <= 1'b0;
`endif
                r_type_s_0r0    <= 1'b 0;	
                r_type_t_0r0    <= 1'b 0;	
                r_type_d_0r0    <= 1'b 0;	
                rx_d_0r0        <= {64{1'b 0}};	
                rx_c_0r0        <= {8{1'b 0}};	
        end
        else
        begin
                if (clk_ena_out == 1'b 1)     
                begin
                        r_type_c_0r0    <= r_type_c_0;	
`ifdef MTIPPCS_EEE_ENA
                        r_type_li_0r0   <= r_type_li_0;
`endif
                        r_type_s_0r0    <= r_type_s_0;	
                        r_type_t_0r0    <= r_type_t_0;	
                        r_type_d_0r0    <= r_type_d_0;	
                        rx_d_0r0        <= rx_d_int;	
                        rx_c_0r0        <= rx_c_int;	
                end
        end
end
//  ------------------------------------------------------------
//  Qualify all 3 blocks with receive statemachine.
//  Considers shifted data blocks by 1. 
//  The stored previous block0 is now block0 output. 

//  Current  block0 is saved for next word
//  ------------------------------------------------------------

//  align hi-ber with pipelines until here to have it aligned with decoder's error counter increment.
//  The Hi-Ber counter is located within the MLD as it must consider Marker blocks.
//  Following the MLD we have:
//  descrambler: 1 clock pipe
//  above block decoder: 1 clock pipe

always @(posedge reset or posedge clk)
begin : process_2
        if (reset == 1'b 1)
        begin
                hi_ber_s <= 1'b 0;	
        end
        else
        begin
                //  two clock-cycle pipes,
                if(clk_ena_out==1'b 1)
                begin
                hi_ber_s <= hi_ber;	
                end
        end
end

//  init condition is for full word (i.e. all blocks)
assign init_cond = r_test_mode | hi_ber_s | ~block_lock; //  r_test_mode + hi_ber + !align_status

//  ------------------------------------------------------------
//  Block0 is previous (saved) block0. It is followed by current block 0. 
//  ------------------------------------------------------------
p8264_block_check82_stm U_CHECK0 (

        .reset                  (reset),
        .clk                    (clk),
        .clk_ena                (clk_ena_out),
        .init_cond              (init_cond),
        .r_type_c               (r_type_c_0r0),
`ifdef MTIPPCS_EEE_ENA
        .r_type_li              (r_type_li_0r0),
        .rx_lpi_active          (rx_lpi_active),
`endif
        .r_type_s               (r_type_s_0r0),
        .r_type_t               (r_type_t_0r0),
        .r_type_d               (r_type_d_0r0),
        .r_type_edt_next        (r_type_edt_0), //  current block 0 is next of previous block 0.
        .state_in               (state_in_0),
        .state_next             (state_next_0),
        .error_out              (error_out_0),
        .rx_init_out            (rx_init_out_0));



//  statemachine state of last block is memorized for next word processing

always @(posedge reset or posedge clk)
begin : process_3
        if (reset == 1'b 1)
        begin	
`ifdef MTIPPCS_EEE_ENA
                state_in_0 <= 3'b 00;
`else
                state_in_0 <= 2'b 00;
`endif
        end
        else
        begin
                if (clk_ena_out == 1'b 1)
                begin
                        state_in_0 <= state_next_0;	
                end
        end
end


//  ----------------------
//  Loop Back ajustment
//  ----------------------

 
always @(posedge reset or posedge clk)
begin
        if (reset == 1'b 1)
        begin
                cgmii_txd_r  <= 64'b0;	
                cgmii_txc_r   <= 8'b0;	
        end
        else if (cgmii_txclk_ena == 1'b1)
        begin
                cgmii_txd_r  <= cgmii_txd;	
                cgmii_txc_r   <= cgmii_txc;
        end
end

//  ----------------------
//  final output register (true pipeline) and loopback.
//  ----------------------
always @(posedge reset or posedge clk)
begin
        if (reset == 1'b 1)
        begin
              loopback_ena_s    <= 4'b 0000;	
              rx_d_out          <= 64'h 000000000100009c;	
              rx_c_out          <= 8'b 00000001;	
              rx_val_out        <= 1'b 0;
              xlgmii_rxt0_next  <= 1'b0;	
        end
        else // NO clk_ena here!
        begin

                //  shift in the loopback to force synthesis to use one bit per lane for lower load and better timing. 
                //  The timely deviation does not matter.

                loopback_ena_s <= {loopback_ena_s[2:0], loopback_ena};	

                //  all output is a pipeline once cycle following clock enable.

                if (loopback_ena_s[3] == 1'b 1)
                begin
                        rx_val_out      <= cgmii_txclk_ena;
                        if (cgmii_txc[0] == 1'b 1 & cgmii_txd[7:0] == 8'h FD)
                        begin
                                xlgmii_rxt0_next <= 1'b1;
                        end
                        else
                        begin
                                xlgmii_rxt0_next <= 1'b0;
                        end	
                end
                else
                begin
                        rx_val_out      <= clk_ena_out | ~block_lock;
                        xlgmii_rxt0_next <= xlgmii_rxt0_next_int;	
                end

                if (loopback_ena_s[0] == 1'b 1)
                begin
                        rx_d_out[63:0]  <= cgmii_txd_r[63:0];	
                        rx_c_out[7:0]   <= cgmii_txc_r[7:0];	
                end

`ifdef MTIPPCS_EEE_ENA
                else if (rx_lpi_active == 1'b 1)
                begin
                        rx_d_out[63:0]  <= 64'h 06_06_06_06_06_06_06_06;	
                        rx_c_out[7:0]   <= 8'b 11111111;			
                end
`endif
      
                else if (rx_init_out_0 == 1'b 1 )
                begin
                        if(ena_clause49==1'b 1)
                           begin
                           rx_d_out[63:0]  <= 64'h 0100009c0100009c;	
                           rx_c_out[7:0]   <= 8'b 00010001;                           
                           end
                        else
                           begin
                           rx_d_out[63:0]  <= 64'h 000000000100009c;	
                           rx_c_out[7:0]   <= 8'b 00000001;
                           end
                end
                else if (error_out_0 == 1'b 1 )
                begin
                        rx_d_out[63:0]  <= 64'h FE_FE_FE_FE_FE_FE_FE_FE;	
                        rx_c_out[7:0]   <= 8'b 11111111;	
                end
                else
                begin
                //  current block 0 is previous block 0
                        rx_d_out[63:0]  <= rx_d_0r0;	
                        rx_c_out[7:0]   <= rx_c_0r0;	
                end

        end
end

//  -----------------------
//  The block error counter for 3 simultaneous blocks
//  -----------------------

assign dec_error =  error_out_0; 

`ifdef MTIPPCS_EEE_ENA
        
        assign err_count_ena = ~init_cond & ~rx_lpi_active;
        
`else
        
        assign err_count_ena = ~init_cond;
         
`endif

sat_counter_evt3 #(22) U_ERRCNT (

        .reset          (reset),
        .clk            (clk),
        .clk_ena        (clk_ena_out),
        .inc_event      ({2'b0,dec_error}),        //  per lane event
        .count_ena      (err_count_ena),    //  allow counting if not in INIT state
        .count_rd       (err_block_count_rd),
        .count_value    (err_block_count));

endmodule // module decode64